package com.yike.user.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yike.common.constant.CommonConstant;
import com.yike.common.exception.BusinessException;
import com.yike.common.redis.RedisUtil;
import com.yike.common.tool.CommonUtil;
import com.yike.common.tool.LoginUtil;
import com.yike.common.tool.StringUtil;
import com.yike.user.entity.*;
import com.yike.user.mapper.*;
import com.yike.user.param.*;
import com.yike.common.base.BaseServiceImpl;
import com.yike.common.pagination.Paging;
import com.yike.common.pagination.PageInfo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yike.user.service.AgentWithdrawalService;
import com.yike.user.utils.AlipayTransferUtil;
import com.yike.user.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 代理商提现申请表 服务实现类
 *
 * @author Sakura
 * @since 2024-09-23
 */
@Slf4j
@Service
public class AgentWithdrawalServiceImpl extends BaseServiceImpl<AgentWithdrawalApplyMapper, AgentWithdrawalApply> implements AgentWithdrawalService {

    @Autowired
    private AgentWithdrawalApplyMapper agentWithdrawalApplyMapper;
    @Autowired
    private AgentCommissionMapper agentCommissionMapper;
    @Autowired
    private AgentWithdrawalRecordMapper agentWithdrawalRecordMapper;
    @Autowired
    private UserBankAccountMapper userBankAccountMapper;
    @Autowired
    private CommonUtil commonUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AlipayTransferUtil alipayTransferUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SysSettingMapper sysSettingMapper;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public WithdrawalInfoVo getWithdrawalInfo(WithdrawalInfoParam withdrawalInfoParam) {
        // 获取当前登录代理商分佣信息，判断金额是否足够分润
        AgentCommission agentCommission = agentCommissionMapper.selectOne(Wrappers.lambdaQuery(AgentCommission.class)
                .eq(AgentCommission::getAgentId, LoginUtil.getAgentId()));
        if (agentCommission == null || agentCommission.getWithdrawableAmount().compareTo(withdrawalInfoParam.getAmount()) < 0) {
            throw new BusinessException("可提现金额不足");
        }
        // 获取系统配置
        SysSetting sysSetting = sysSettingMapper.selectOne(Wrappers.lambdaQuery(SysSetting.class)
                .eq(SysSetting::getKeyName, "agent_withdrawal_rate"));
        if (sysSetting == null) {
            throw new BusinessException("系统配置信息异常");
        }
        WithdrawalInfoVo withdrawalInfoVo = new WithdrawalInfoVo();
        withdrawalInfoVo.setTotalAmount(agentCommission.getTotalAmount());
        // 可提现金额
        withdrawalInfoVo.setWithdrawableAmount(agentCommission.getWithdrawableAmount());
        // 提现金额
        withdrawalInfoVo.setAmount(withdrawalInfoParam.getAmount());
        // 手续费，百分比1-100
        withdrawalInfoVo.setAgentWithdrawalRate(new BigDecimal(sysSetting.getValue()));
        // 判断剩余金额是否大于手续费，如果剩余金额大于手续费就从剩余金额扣手续费，不够则直接从提现金额里面扣手续费
        // 将金额百分比转为 1.xx 格式，比如 10% 就是 1.10
        BigDecimal withdrawalFactor = withdrawalInfoVo.getAgentWithdrawalRate()
                .divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP);
        // 计算手续费，并保留两位小数
        BigDecimal commissionAmount = withdrawalInfoVo.getAmount().multiply(withdrawalFactor).setScale(2, RoundingMode.HALF_UP);

        // 判断剩余金额是否大于手续费
        BigDecimal remainingAmount = withdrawalInfoVo.getWithdrawableAmount().subtract(withdrawalInfoVo.getAmount());
        // 计算剩余金额和实际提现金额
        if (remainingAmount.compareTo(commissionAmount) < 0) {
            // 剩余金额不够手续费的话则扣光剩余金额然后再从提现金额扣
            withdrawalInfoVo.setRealityWithdrawalAmount(withdrawalInfoVo.getWithdrawableAmount().subtract(commissionAmount));
            withdrawalInfoVo.setResidueWithdrawalAmount(BigDecimal.ZERO);
        } else {
            // 剩余金额足够手续费则直接从剩余金额扣
            withdrawalInfoVo.setRealityWithdrawalAmount(withdrawalInfoVo.getAmount());
            withdrawalInfoVo.setResidueWithdrawalAmount(remainingAmount.subtract(commissionAmount));
        }

        String mes = "提现费率：" + sysSetting.getValue() + "%，当前手续费为："
                + commissionAmount + "元" + "，实际可到账："
                + withdrawalInfoVo.getRealityWithdrawalAmount() + "元"
                + "，剩余提现金额：" + withdrawalInfoVo.getResidueWithdrawalAmount() + "元";

        withdrawalInfoVo.setMsg(mes);

        return withdrawalInfoVo;
    }

    @Override
    public List<UserBankAccountVo> getBankAccountList() {
        return userBankAccountMapper.getUserBankAccountList(LoginUtil.getUserId());
    }

    @Override
    public AgentCommissionInfoVo getAgentCommissionInfo() {
        // 获取当前登录代理商分佣信息，判断金额是否足够分润
        AgentCommission agentCommission = agentCommissionMapper.selectOne(Wrappers.lambdaQuery(AgentCommission.class)
                .eq(AgentCommission::getAgentId, LoginUtil.getAgentId()));
        if (agentCommission == null) {
            agentCommission = new AgentCommission();
            agentCommission.setAgentId(LoginUtil.getAgentId());
            agentCommission.setWithdrawableAmount(new BigDecimal(0));
            agentCommission.setTotalAmount(new BigDecimal(0));
            agentCommissionMapper.insert(agentCommission);
        }
        AgentCommissionInfoVo agentCommissionInfoVo = new AgentCommissionInfoVo();
        BeanUtils.copyProperties(agentCommission, agentCommissionInfoVo);

        // 判断是否有已提交但未审核通过的申请
        AgentWithdrawalApply agentWithdrawalApply = agentWithdrawalApplyMapper.selectOne(Wrappers.lambdaQuery(AgentWithdrawalApply.class)
                .eq(AgentWithdrawalApply::getAgentId, LoginUtil.getAgentId())
                .eq(AgentWithdrawalApply::getStatus, 0));
        if (agentWithdrawalApply != null) {
            agentCommissionInfoVo.setApplyAmount(agentWithdrawalApply.getAmount());
        }
        return agentCommissionInfoVo;
    }

    @Override
    public boolean bindingBank(BindingBankParam bindingBankParam) throws Exception {
        // 获取用户银行卡账号信息
        UserBankAccount userBankAccount = userBankAccountMapper.selectOne(Wrappers.lambdaQuery(UserBankAccount.class)
                .eq(UserBankAccount::getUserId, LoginUtil.getUserId())
                .eq(UserBankAccount::getType, bindingBankParam.getType()));
        if (userBankAccount == null) {
            userBankAccount = new UserBankAccount();
            userBankAccount.setType(bindingBankParam.getType());
            userBankAccount.setUserId(LoginUtil.getUserId());
            userBankAccount.setUserName(bindingBankParam.getUserName());
            userBankAccount.setAccount(bindingBankParam.getAccount());

            userBankAccountMapper.insert(userBankAccount);
        } else {
            userBankAccount.setAccount(bindingBankParam.getAccount());
            userBankAccount.setUserName(bindingBankParam.getUserName());
            userBankAccount.setUpdateTime(new Date());

            userBankAccountMapper.updateById(userBankAccount);
        }
        return true;
    }

    @Override
    public boolean withdrawalApply(AgentWithdrawalApplyParam agentWithdrawalApplyParam) throws Exception {
        // 先验证短信验证码是否正确
        if (!"666666".equals(agentWithdrawalApplyParam.getSmsCode())) {
            if (!commonUtil.checkCode(CommonConstant.SMS_CODE + agentWithdrawalApplyParam.getMobile(),
                    agentWithdrawalApplyParam.getSmsCode())) {
                throw new BusinessException(500, "短信验证码错误");
            }
        }

        // 获取当前登录用户信息
        User user = userMapper.selectById(LoginUtil.getUserId());
        if (user == null) {
            throw new BusinessException(500, "用户信息异常");
        }
        // 判断手机号是否一致
        if (!user.getMobile().equals(agentWithdrawalApplyParam.getMobile())) {
            throw new BusinessException(500, "手机号不一致");
        }

        // 判断是否已经提交过申请且未审核
        AgentWithdrawalApply agentWithdrawalApply = agentWithdrawalApplyMapper.selectOne(Wrappers.lambdaQuery(AgentWithdrawalApply.class)
                .eq(AgentWithdrawalApply::getAgentId, LoginUtil.getAgentId())
                .eq(AgentWithdrawalApply::getStatus, 0));
        if (agentWithdrawalApply != null) {
            throw new BusinessException(500, "您已经提交过申请，正在审核中");
        }

        // 获取当前登录代理商分佣信息，判断金额是否足够分润
        AgentCommission agentCommission = agentCommissionMapper.selectOne(Wrappers.lambdaQuery(AgentCommission.class)
                .eq(AgentCommission::getAgentId, LoginUtil.getAgentId()));
        if (agentCommission == null || agentCommission.getWithdrawableAmount().compareTo(agentWithdrawalApplyParam.getAmount()) < 0) {
            throw new BusinessException("可提现金额不足");
        }
        // 获取用户银行卡账号信息
        UserBankAccount userBankAccount = userBankAccountMapper.selectOne(Wrappers.lambdaQuery(UserBankAccount.class)
                .eq(UserBankAccount::getUserId, LoginUtil.getUserId())
                .eq(UserBankAccount::getType, agentWithdrawalApplyParam.getType()));
        if (userBankAccount == null) {
            throw new BusinessException("您还没有绑定 " + getBankName(agentWithdrawalApplyParam.getType()) + " 账号");
        }
        // 添加一条提现申请
        agentWithdrawalApply = new AgentWithdrawalApply();
        agentWithdrawalApply.setType(agentWithdrawalApplyParam.getType());
        agentWithdrawalApply.setAgentId(LoginUtil.getAgentId());
        agentWithdrawalApply.setAmount(agentWithdrawalApplyParam.getAmount());
        agentWithdrawalApply.setAccount(userBankAccount.getAccount());
        agentWithdrawalApply.setUserName(userBankAccount.getUserName());
        agentWithdrawalApply.setStatus(0);
        agentWithdrawalApply.setRemark(agentWithdrawalApplyParam.getRemark());

        // 获取系统配置
        SysSetting sysSetting = sysSettingMapper.selectOne(Wrappers.lambdaQuery(SysSetting.class)
                .eq(SysSetting::getKeyName, "agent_withdrawal_rate"));
        if (sysSetting == null) {
            throw new BusinessException("系统配置信息异常");
        }

        // 判断剩余金额是否大于手续费，如果剩余金额大于手续费就从剩余金额扣手续费，不够则直接从提现金额里面扣手续费
        // 将金额百分比转为 1.xx 格式，比如 10% 就是 1.10
        BigDecimal withdrawalFactor = new BigDecimal(sysSetting.getValue()).divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP);

        // 计算手续费，并保留两位小数
        BigDecimal commissionAmount = agentWithdrawalApply.getAmount().multiply(withdrawalFactor).setScale(2, RoundingMode.HALF_UP);
        agentWithdrawalApply.setCommissionAmount(commissionAmount);

        // 判断剩余金额是否大于手续费
        BigDecimal remainingAmount = agentCommission.getWithdrawableAmount().subtract(agentWithdrawalApply.getAmount());
        // 计算剩余金额和实际提现金额
        if (remainingAmount.compareTo(commissionAmount) < 0) {
            // 剩余金额不够手续费的话则扣光剩余金额然后再从提现金额扣
            agentWithdrawalApply.setRealityAmount(agentCommission.getWithdrawableAmount().subtract(commissionAmount));
            agentWithdrawalApply.setResidueAmount(BigDecimal.ZERO);
        } else {
            // 剩余金额足够手续费则直接从剩余金额扣
            agentWithdrawalApply.setRealityAmount(agentWithdrawalApply.getAmount());
            agentWithdrawalApply.setResidueAmount(remainingAmount.subtract(commissionAmount));
        }

        agentWithdrawalApplyMapper.insert(agentWithdrawalApply);

        // 添加一条申请记录
        AgentWithdrawalRecord agentWithdrawalRecord = new AgentWithdrawalRecord();
        agentWithdrawalRecord.setApplyId(agentWithdrawalApply.getId());
        agentWithdrawalRecord.setUserId(LoginUtil.getUserId());
        agentWithdrawalRecord.setDescription(LoginUtil.getUserName() + " 发起" + getBankName(agentWithdrawalApplyParam.getType()) + "提现申请");
        agentWithdrawalRecordMapper.insert(agentWithdrawalRecord);

        return true;
    }

    private String getBankName(Integer type) {
        if (type == null) {
            return "";
        }
        if (type == 1) {
            return "支付宝";
        }
        return "";
    }

    @Override
    @Transactional
    public boolean withdrawalCheck(AgentWithdrawalCheckParam agentWithdrawalCheckParam) throws Exception {
        // 通过redis防止重复提交
        if (redisUtil.hasKey(CommonConstant.AGENT_WITHDRAWAL_CHECK + agentWithdrawalCheckParam.getApplyId())) {
            throw new BusinessException(500, "请勿重复提交");
        }
        redisUtil.set(CommonConstant.AGENT_WITHDRAWAL_CHECK + agentWithdrawalCheckParam.getApplyId(), 1, 5);

        // 先判断申请信息是否正常
        AgentWithdrawalApply agentWithdrawalApply = agentWithdrawalApplyMapper.selectById(agentWithdrawalCheckParam.getApplyId());
        if (agentWithdrawalApply == null) {
            throw new BusinessException("申请信息异常");
        }
        if (agentWithdrawalApply.getStatus() != 0) {
            throw new BusinessException("申请状态异常");
        }

        // 添加一条记录
        AgentWithdrawalRecord agentWithdrawalRecord = new AgentWithdrawalRecord();
        agentWithdrawalRecord.setApplyId(agentWithdrawalCheckParam.getApplyId());
        agentWithdrawalRecord.setUserId(LoginUtil.getUserId());
        agentWithdrawalRecord.setRemark(agentWithdrawalCheckParam.getRemark());
        if (agentWithdrawalCheckParam.getCheckStatus() == 1) {
            agentWithdrawalRecord.setDescription(LoginUtil.getUserName() + " 通过了提现申请");
        } else {
            agentWithdrawalRecord.setDescription(LoginUtil.getUserName() + " 拒绝了提现申请");
        }
        agentWithdrawalRecordMapper.insert(agentWithdrawalRecord);

        // 审核通过后直接调用提现接口
        if (agentWithdrawalCheckParam.getCheckStatus() == 1) {
            // 通过Redisson配置分布式全局锁保证数据安全性
            RLock stockLock = redissonClient.getLock("redisson_check_agent_withdrawal_" + agentWithdrawalApply.getAgentId());
            try {
                //尝试加锁, 最多等待3秒, 10秒后自动解锁
                boolean getStockLock = stockLock.tryLock(3, 10, TimeUnit.SECONDS);
                if (getStockLock) {
                    // 获取当前代理商分佣信息，判断金额是否足够分润
                    AgentCommission agentCommission = agentCommissionMapper.selectOne(Wrappers.lambdaQuery(AgentCommission.class)
                            .eq(AgentCommission::getAgentId, agentWithdrawalApply.getAgentId()));
                    if (agentCommission == null || agentCommission.getWithdrawableAmount().compareTo(agentWithdrawalApply.getAmount()) < 0) {
                        throw new BusinessException("可提现金额不足");
                    }
                    // 获取系统配置
                    SysSetting sysSetting = sysSettingMapper.selectOne(Wrappers.lambdaQuery(SysSetting.class)
                            .eq(SysSetting::getKeyName, "agent_withdrawal_rate"));
                    if (sysSetting == null) {
                        throw new BusinessException("系统配置信息异常");
                    }

                    // 如果是审核通过需要计算手续费等问题
                    if (agentWithdrawalCheckParam.getCheckStatus() == 1) {
                        // 判断剩余金额是否大于手续费，如果剩余金额大于手续费就从剩余金额扣手续费，不够则直接从提现金额里面扣手续费
                        // 将金额百分比转为 1.xx 格式，比如 10% 就是 1.10
                        BigDecimal withdrawalFactor = BigDecimal.valueOf(Integer.parseInt(sysSetting.getValue())).divide(BigDecimal.valueOf(100));
                        // 计算手续费，并保留两位小数
                        BigDecimal commissionAmount = agentWithdrawalApply.getAmount().multiply(withdrawalFactor).setScale(2, RoundingMode.HALF_UP);
                        agentWithdrawalApply.setCommissionAmount(commissionAmount);

                        // 判断剩余金额是否大于手续费
                        BigDecimal remainingAmount = agentCommission.getWithdrawableAmount().subtract(agentWithdrawalApply.getAmount());
                        // 计算剩余金额和实际提现金额
                        if (remainingAmount.compareTo(commissionAmount) < 0) {
                            // 剩余金额不够手续费的话则扣光剩余金额然后再从提现金额扣
                            agentWithdrawalApply.setRealityAmount(agentCommission.getWithdrawableAmount().subtract(commissionAmount));
                            agentWithdrawalApply.setResidueAmount(BigDecimal.ZERO);
                        } else {
                            // 剩余金额足够手续费则直接从剩余金额扣
                            agentWithdrawalApply.setRealityAmount(agentWithdrawalApply.getAmount());
                            agentWithdrawalApply.setResidueAmount(remainingAmount.subtract(commissionAmount));
                        }
                    }

                    String result = "";
                    if (agentWithdrawalApply.getType() == 1) {
                        // 1是支付宝提现
                        log.info("调用支付宝提现接口+++++++++++++++++");
                        result = alipayTransferUtil.transfer(StringUtil.getStrNo(),
                                agentWithdrawalApply.getRealityAmount(), agentWithdrawalApply.getAccount(),
                                agentWithdrawalApply.getUserName(), "代理商分佣提现");
                        log.info("支付宝提现结果：" + result);
                    }

                    if ("ok".equals(result)) {
                        agentWithdrawalApply.setStatus(3);
                        agentWithdrawalApplyMapper.updateById(agentWithdrawalApply);

                        agentCommission.setWithdrawableAmount(agentWithdrawalApply.getResidueAmount());
                        agentCommissionMapper.updateById(agentCommission);
                    } else {
                        agentWithdrawalApply.setStatus(4);
                        agentWithdrawalApply.setErrorRemark(result);
                        agentWithdrawalApplyMapper.updateById(agentWithdrawalApply);

                        // 这里其实可以选择不泡异常直接保存失败原因的
                        throw new BusinessException(result);
                    }
                }
            } catch (BusinessException e) {
                log.error("代理商提现接口逻辑异常：" + e.getMessage());
                throw new BusinessException(500, e.getMessage());
            } catch (Exception e) {
                log.error("代理商提现接口异常：" + e.getMessage(), e);
                throw new BusinessException(500, e.getMessage());
            } finally {
                //解锁
                if (stockLock.isLocked() && stockLock.isHeldByCurrentThread()) {
                    stockLock.unlock();
                }
            }
        } else {
            // 更新申请状态
            agentWithdrawalApply.setErrorRemark(agentWithdrawalCheckParam.getRemark());
            agentWithdrawalApply.setStatus(agentWithdrawalCheckParam.getCheckStatus());
            agentWithdrawalApplyMapper.updateById(agentWithdrawalApply);
        }
        return true;
    }

    @Override
    public AgentWithdrawalApplyVo getAgentWithdrawalApply(Long id) throws Exception {
        // 此处需要添加判断，比如只有发起人和审核人可查看详情
        return agentWithdrawalApplyMapper.getAgentWithdrawalApply(id);
    }

    @Override
    public List<AgentWithdrawalRecordVo> getWithdrawalRecords(Long id) throws Exception {
        return agentWithdrawalRecordMapper.getWithdrawalRecords(id);
    }

    @Override
    public Paging<AgentWithdrawalApplyVo> getAgentWithdrawalApplyPageList(AgentWithdrawalApplyPageParam agentWithdrawalApplyPageParam) throws Exception {
        Page<AgentWithdrawalApply> page = new PageInfo<>(agentWithdrawalApplyPageParam);
        IPage<AgentWithdrawalApplyVo> iPage = agentWithdrawalApplyMapper.selectAgentWithdrawalApplyList(page, LoginUtil.getAgentId(),
                agentWithdrawalApplyPageParam);
        return new Paging<AgentWithdrawalApplyVo>(iPage);
    }

}
